﻿/**************************************************************************
**
**  MisCip
**  ~~~~~~~~~~
**
**  Form1.cs: 
**  ---------
**  Erstellt das Hauptfenster mit deren Zusatzfunktionen
**
**  
**************************************************************************/

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.IO;
using System.IO.Ports;

namespace Pic_Simulator
{
    public partial class MisCip : Form
    {
        const int MAX_REGISTER = 256;
        //Variablen für die Simulation
        bool codeRunning;
        bool sleepMode;
        bool bank0;
        bool bOpenedFile = false;
        int iDelay;  //Verzögerung zwischen den Assemblerbefehlen in der Simulation
        int iPC;    //Programmcounter
        long lCycles, lRuntime; //Zyklen und Laufzeit
        long lWatchdog;  //Watchdogzähler
        bool timer0enabled = true;
        int iPrescalercnt;
        int iPrescalerValue;
        //RB-Port Änderung
        int iRA, iRB;   //Hilfsvariablen, um Änderung an RA und RB festzustellen
        //------Simulator-Register

        //Array für Register
        int[] iReg = new int[MAX_REGISTER];
        //Stack als echten LIFO(Stack) realisiert
        Stack<int> stack = new Stack<int>(8);
        //W Register;
        int iWReg;

        //Objekt um für Behandlung der eingelesenen Dateien
        FileReader obFileReader = new FileReader();

        //Bool für SerialConnection
        bool bSerialCon = false;

        //Bool für WatchDog
        bool bWatchdog = false;

        //Objekt für decoder
        Decoder obDecoder = new Decoder();

        //Array für EEPROM
        int[] iEEPROM = new int[64];

        //----------
        List<String> list = new List<String>();

        //Konstruktor
        public MisCip()
        {
            int[] iReg = new int[MAX_REGISTER];
            iDelay = 250;
            lCycles = 0;
            lRuntime = 0;
            lWatchdog = 0;
            iPrescalercnt = 0;
            timer0enabled = true;
            sleepMode = false;
            bank0 = true;
            bWatchdog = false;
            iRA = 0x00; //
            iRB = 0x00;
            //Initialisierung/Reset der Register etc.
            SimStartup();
            InitializeComponent();
            openFileDialog1.Filter = "txt files (*.txt)|*.txt|LST Files (*.lst)|*.lst";
            refreshReg();
            searchForPorts();
        }

        /*********************************************************************/
        /**   SimReset
        **
        **  Verursacht einen normalen, nicht Hardware, Reset
        **
        **  Ret: void
        **
        **************************************************************************/

        private delegate void SimResetDelegate();
        private void SimReset()
        {
            if (InvokeRequired)
            {
                var invokeVar = new SimResetDelegate(SimReset);
                Invoke(invokeVar);
            }
            else
            {
                iPC = 0;
                //Bank 0
                iReg[0x03] = iReg[0x03] & 0x1F;
                iReg[0x05] = iReg[0x05] & 0x1F;
                iReg[0x0B] = iReg[0x0B] & 0x01;
                //Bank 1
                iReg[0x81] = 0xFF;
                iReg[0x83] = iReg[0x83] | 0x18; iReg[0x83] = iReg[0x83] & 0x1F;
                iReg[0x85] = 0x1F;
                iReg[0x86] = 0xFF;
                iReg[0x88] = iReg[0x88] & 0x08;
                for (int i = 0; i <= 255; i++)
                {
                    if (i != 0x03)
                        if (i != 0x05)
                            if (i != 0x06)
                                if (i != 0x0B)
                                    if (i != 0x81)
                                        if (i != 0x83)
                                            if (i != 0x85)
                                                if (i != 0x86)
                                                    if (i != 0x88)
                                                    {
                                                        iReg[i] = 0x00;
                                                    }
                }

                iWReg = 0;
                stack.Clear(); //Stack leeren
                FocusListCode(obFileReader.ReferenceList[0] - 1);

                refreshReg();
            }
        }

        /*********************************************************************/
        /**   SimStartup
        **
        **  Verursacht einen Hardwarereset (Power-On)
        **
        **  Ret: void
        **
        **************************************************************************/

        private delegate void SimStartupDelegate();
        private void SimStartup()
        {
            if (InvokeRequired)
            {
                var invokeVar = new SimStartupDelegate(SimStartup);
                Invoke(invokeVar);
            }
            else
            {
                iPC = 0;
                //Bank 0
                iReg[0x03] = iReg[0x03] | 0x18; iReg[0x03] = iReg[0x03] & 0x1F;
                iReg[0x05] = iReg[0x05] & 0x1F;
                iReg[0x0B] = iReg[0x0B] & 0x01;
                //Bank 1
                iReg[0x81] = 0xFF;
                iReg[0x83] = iReg[0x83] | 0x18; iReg[0x83] = iReg[0x83] & 0x1F;
                iReg[0x85] = 0x1F;
                iReg[0x86] = 0xFF;
                iReg[0x88] = iReg[0x88] & 0x08;

                iWReg = 0;
                stack.Clear(); //Stack leeren

                for (int i = 0; i <= 255; i++)
                {
                    if (i != 0x03)
                        if (i != 0x05)
                            if (i != 0x06)
                                if (i != 0x0B)
                                    if (i != 0x81)
                                        if (i != 0x83)
                                            if (i != 0x85)
                                                if (i != 0x86)
                                                    if (i != 0x88)
                                                    {
                                                        iReg[i] = 0x00;
                                                    }
                }

                if (bOpenedFile)
                {
                    lCycles = 0;
                    lRuntime = 0;
                    FocusListCode(obFileReader.ReferenceList[0] - 1);
                    refreshReg();
                }
            }

        }

        /*********************************************************************/
        /**   listCode_DoubleClick
        **
        **  BreakPoint setzen bei Doppelklick auf Zeile
        **
        **  Ret: void
        **
        **************************************************************************/

        private void listCode_DoubleClick(object sender, EventArgs e)
        {
            int iLines = Convert.ToInt32( listCode.Items.Count.ToString() );
            for (int i = 0; i < iLines; i++)
            {
                if (listCode.Items[i].Selected == true)
                {
                    if (string.Compare( listCode.Items[i].Text.Substring(0, 4), "    ") == 1)
                    {
                        if (listCode.Items[i].ToString().Contains("•"))
                        {
                            listCode.Items[i].Text = listCode.Items[i].Text.ToString().Replace("•", "");
                            listCode.Items[i].BackColor = Color.White;
                        }
                        else
                        {
                            string sLine = listCode.Items[i].Text.ToString();
                            listCode.Items[i].Text = "•" + sLine;
                            listCode.Items[i].BackColor = Color.Red;
                        }
                    }
                }
            }
        }

        /*********************************************************************/
        /**   checkBreakPoint
        **
        **  Überprüfen ob aktuelle Zeile ein Breakpoint ist
        **
        **  Ret: bool
        **
        **************************************************************************/

        private bool checkBreakPoint()
        {
            int iLines = Convert.ToInt32(listCode.Items.Count.ToString());
            for (int i = 0; i < iLines; i++)
            {
                if (listCode.Items[i].Selected == true)
                {
                    if (listCode.Items[i].ToString().Contains("•"))
                    {
                        Stop();
                        return true;
                    }
                    else
                    {
                        return false;
                    }
                }
            }
            return false;
        }

        /*********************************************************************/
        /**   oeffnenToolStripMenuItem_Click
        **
        **  Funktion um Datei zu öffnen
        **
        **  Ret: void
        **
        **************************************************************************/

        private void oeffnenToolStripMenuItem_Click(object sender, EventArgs e)
        {
            using (OpenFileDialog Dialog = new OpenFileDialog())
            {
                DialogResult Result;
                Dialog.CheckFileExists = true;
                Dialog.Title = "Datei Laden";
                Dialog.Filter = "Lst-Dateien|*.lst";
                Dialog.RestoreDirectory = true;

                Result = Dialog.ShowDialog();

                if (Result == DialogResult.OK)
                {
                    bOpenedFile = true;
                    obFileReader = new FileReader();
                    bStart.Enabled = true;
                    bStep.Enabled = true;
                    //SimReset();
                    tbLoadProg.Text = Dialog.FileName;

                    obFileReader.FillCodeArray(Dialog.FileName);

                    obFileReader.readAllCmds();
                    listCode.Items.Clear();

                    //Zeilen einlesen
                    for (int i = 0; i < obFileReader.CodeLines.Length; i++)
                    {
                        listCode.Items.Add(obFileReader.CodeLines[i]);
                    }

                    //Erster zu ausführende Befehl wird markiert
                    FocusListCode(obFileReader.ReferenceList[0] - 1);
                    //Reset
                    SimReset();
                    refreshReg();
                }
            }
        }

        /*********************************************************************/
        /**   beendenToolStripMenuItem_Click
        **
        **  Funktion das Programm über das Menü zu schliessen
        **
        **  Ret: void
        **
        **************************************************************************/

        private void beendenToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Close();
        }

        /*********************************************************************/
        /**   buttonStart_Click
        **
        **  Startet das Programm über einen eigenen Thread
        **
        **  Ret: void
        **
        **************************************************************************/

        private void buttonStart_Click(object sender, EventArgs e)
        {
            //running auf true setzen
            codeRunning = true;
            //Threads anlegen
            iDelay = Convert.ToInt32(cbDelay.SelectedItem);
            Thread simulateThread = new Thread(simulateProgram);
            simulateThread.Start(); //Programmablauf
            bStart.Enabled = false;
            bStep.Enabled = false;
            bStop.Enabled = true;
        }

        /*********************************************************************/
        /**   watchdog
        **
        **  Überprüft den WatchDog
        **
        **  Ret: void
        **
        **************************************************************************/

        private void watchdog()
        {
            if (bWatchdog)
            {
                if ((iReg[0x81] & 0x08) == 0x00) //Prescaler TMR0 zugewiesen?
                {
                    ExecuteWDT();     //.. dann Ratio 1:1
                }
                else  //Prescaler WDT zugewiesen
                {
                    iPrescalercnt++;
                    if (iPrescalercnt >= iPrescalerValue)  //ansonsten Prescalratio(mindestens 1:1)
                    {
                        iPrescalercnt = 0;
                        ExecuteWDT();
                    }
                }
            }  
        }

        /*********************************************************************/
        /**   ExecuteWDT
        **
        **  Watchdog hochzählen und Interrupt bei Überlauf
        **
        **  Ret: void
        **
        **************************************************************************/

        private void ExecuteWDT()
        {
            lWatchdog++;
            if (lWatchdog >= 18000 * 5)     //18ms, da 200ns pro Zyklus!
            {
                //TimeOut-Flag setzen
                iReg[0x03] &= 0xEF; 
                iReg[0x83] &= 0xEF;
                //Löse Reset aus
                SimReset();     //Simulator zurücksetzen!
                lWatchdog = 0;  //Watchdog zurücksetzen
                sleepMode = false;
            }
        }

        /*********************************************************************/
        /**   simulateTimer0
        **
        **  Simuliert den TMR0
        **
        **  Ret: void
        **
        **************************************************************************/

        private void simulateTimer0()
        {
            if (timer0enabled)
            {
                if ((iReg[0x81] & 0x20) == 0) //Timer0 in Timer-Mode?
                {
                    if ((iReg[0x81] & 0x08) == 0x08) //Prescaler WDT zugewiesen?
                    {
                        ExecuteTimer(); //Ratio 1:1
                    }
                    else //Prescaler TMR0 zugewiesen? dann Ratio 1:x
                    {
                        iPrescalercnt++;
                        if (iPrescalercnt >= iPrescalerValue)
                        {
                            iPrescalercnt = 0;
                            ExecuteTimer();
                        }
                    }
                }
                else   //Prescaler wird auch beim Counter verwendet
                {
                    ExecuteTimer();
                }
            }
          }

        /*********************************************************************/
        /**   ExecuteTimer
        **
        **  Führt den Timer aus
        **
        **  Ret: void
        **
        **************************************************************************/

        private void ExecuteTimer()
        {
            if ((iReg[0x81] & 0x20) == 0)    //Timer0 in Timer-Mode?
            {
                iReg[0x01]++;   //Timer inkrementieren
                if (iReg[0x01] > 255)   //Timer-Überlauf? *iPrescalervalue?
                {
                    iReg[0x0B] |= 0x04;     //Timerinterruptflag setzen
                    iReg[0x01] = 0; //Timer zurücksetzen
                    Console.WriteLine("Timer0 Überlauf TimerMode");
                }
            }
            else   //Timer0 in Counter-Mode?
            {
                if (((iReg[0x05] & 0x10) > 0) && ((iRA & 0x10)) == 0) //Wechsel von 0 auf 1?
                {
                    iRA = iRA | 0x10; //Hilfsvariable aktualisieren

                    if ((iReg[0x81] & 0x10) == 0)   //Jede ansteigende Taktflanke zählen
                    {
                        iPrescalercnt++;
                        if (iPrescalercnt >= iPrescalerValue)
                        {
                            iPrescalercnt = 0;
                            iReg[0x01]++; //Timer inkrementieren
                        }
                    }
                }
                else if (((iReg[0x05] & 0x10) == 0) && ((iRA & 0x10) > 0))   //Wechsel von 1 auf 0?
                {
                    iRA = iRA & 0xEF; //Hilfsvariable aktualisieren
                    if ((iReg[0x81] & 0x10) > 1)        //Jede fallende Taktflanke zählen
                    {
                        iPrescalercnt++;
                        if (iPrescalercnt >= iPrescalerValue)
                        {
                            iPrescalercnt = 0;
                            iReg[0x01]++; //Timer inkrementieren
                        }
                    }
                }
                if (iReg[0x01] > 255) //Counter-Überlauf?
                {
                    iReg[0x0B] |= 0x04;     //Timerinterruptflag setzen
                    iReg[0x01] = 0; //Timer inkrementieren
                    Console.WriteLine("Timer0 Überlauf CounterMode");
                }
            }
       }

        /*********************************************************************/
        /**   simulateProgram
        **
        **  Endlosschleife solange der Thread läuft (nachdem "Start"-Gedrückt wurde)
        **
        **  Ret: void
        **
        **************************************************************************/

        private void simulateProgram()
        {
            while (codeRunning)
            {
                ExecuteCmd();
                Thread.Sleep(iDelay);
            }
        }

        /*********************************************************************/
        /**   bStop_Click
        **
        **  Pausiert das Programm
        **
        **  Ret: void
        **
        **************************************************************************/

        private void bStop_Click(object sender, EventArgs e)
        {
            codeRunning = false;
            Stop();
        }

        /*********************************************************************/
        /**   bStop_Click
        **
        **  Schliesst das Programm über den Menü-Eintrag "Beenden"
        **
        **  Ret: void
        **
        **************************************************************************/

        private void MainWindow_FormClosing(object sender, FormClosingEventArgs e)
        {
            Stop();
        }

        /*********************************************************************/
        /**   Stop
        **
        **  Pausiert das Programm
        **
        **  Ret: void
        **
        **************************************************************************/

        private delegate void StopDelegate();
        private void Stop()
        {
            if (InvokeRequired)
            {
                var invokeVar = new StopDelegate(Stop);
                Invoke(invokeVar);
            }
            else
            {
                codeRunning = false;
                bStart.Enabled = true;
                bStep.Enabled = true;
                bStop.Enabled = false;
                //Buttons disablen..
            }
        }


        /*********************************************************************/
        /**   bReset_Click
        **
        **  Resettet das Programm (nicht HardwareReset!)
        **
        **  Ret: void
        **
        **************************************************************************/

        private void bReset_Click(object sender, EventArgs e)
        {
            codeRunning = false;
            SimReset();
        }

        /*********************************************************************/
        /**   bStep_Click
        **
        **  Führt einen einzelnen Schritt aus
        **
        **  Ret: void
        **
        **************************************************************************/

        private void bStep_Click(object sender, EventArgs e)
        {
            //ueberpruefen ob Datei eingelesen ist
            //if (listCode.Columns[0].Text != "")   
            ExecuteCmd();
        }

        /*********************************************************************/
        /**   checkinterrupt
        **
        **  Schaut ob ein Interrupt ausgelöst wird
        **
        **  Ret: void
        **
        **************************************************************************/

        private void checkinterrupt()
        {
            //-------Set Interrupts -----
            //Interruptflags setzen wenn Bedingung erfüllt
            //Timer0 in extra Thread! siehe oben
            //RB0/INT set //Nur das 0. Bit abfragen
            if (((iReg[0x06] & 0x01) == 1) && ((iRB & 0x01) == 0))   //Wechsel von 0 auf 1? //Flankenwechsel?
            {
                iRB = iRB | 0x01;
                //iRB = (iReg[0x06] & 0x01);
                if ((iReg[0x81] & 0x40) > 0)
                {
                    iReg[0x0B] |= 0x02;
                }
            }
            else if (((iReg[0x06] & 0x01) == 0) && ((iRB & 0x01)) > 0) //Wechsel von 1 auf 0?
            {
                iRB = iRB & 0xFE;
                // iRB = (iReg[0x06] & 0x01);
                if ((iReg[0x81] & 0x40) == 0)
                {
                    iReg[0x0B] |= 0x02;
                }
            }

            //RB-Port changed (1 of Bit 4-7)
            if (((iReg[0x06] & 0xF0 ) ^ (iRB & 0xF0)) > 0)
            {
                int hilf;
                hilf = iRB & 0x0F;
                iRB = (iReg[0x06] & 0xF0);
                iRB |= hilf;

                iReg[0x0B] |= 0x01;
            }
            //-------Set Interrupts Ende ---- 
            //Auf Globalinterrupt enabled überprüfen
            if ((iReg[0x0B] & 0x80) > 0)     //Globalinterrupt enabled?
            {
                // Einzelne Intterupts überprüfen, Priorität?
                if ((iReg[0x0B] & 0x24) >= 0x24)    //Timer0 enabled und Überlauf aufgetreten?
                {
                    //Aktuelle Adresse im Stack speichern wegen RETFIE
                    stack.Push(iPC);
                    //Springe zu Adress 0x04 und führe alle aufgetretenen Interrupts aus
                    iPC = 0x04;
                    iReg[0x0B] &= 0x7F; iReg[0x8B] &= 0x7F; //Global Interrupt löschen, damit keine Endlosschleife entsteht
                }
                else if ((iReg[0x0B] & 0x12) >= 0x12)    //RB0/Int enabled und Interrupt aufgetreten?
                {
                    //Aktuelle Adresse im Stack speichern wegen RETFIE
                    stack.Push(iPC);
                    //Springe zu Adress 0x04 und führe alle aufgetretenen Interrupts aus
                    iPC = 0x04;
                    iReg[0x0B] &= 0x7F; iReg[0x8B] &= 0x7F; //Global Interrupt löschen, damit keine Endlosschleife entsteht
                    //  iReg[0x0B] &= 0xFD;     //Interruptflag löschen  Macht der User selbst in der ISR!?
                }
                else if ((iReg[0x0B] & 0x09) >= 0x09)    //RB-Port changed enabled und Interrupt aufgetreten?
                {
                    sleepMode = false;  //Pic wecken
                    //Aktuelle Adresse im Stack speichern wegen RETFIE
                    stack.Push(iPC);
                    //Springe zu Adress 0x04 und führe alle aufgetretenen Interrupts aus
                    iPC = 0x04;
                    iReg[0x0B] &= 0x7F; iReg[0x8B] &= 0x7F; //Global Interrupt löschen, damit keine Endlosschleife entsteht
                    //  iReg[0x0B] &= 0xFE;     //Interruptflag löschen  Macht der User selbst in der ISR!?
                }
                else if (((iReg[0x88] & 0x10) > 0) && ((iReg[0x0B] & 0x40) > 0))    //EEPROM-Write finished Interrupt
                {
                    sleepMode = false;  //Pic wecken
                    //Aktuelle Adresse im Stack speichern wegen RETFIE
                    stack.Push(iPC);
                    //Springe zu Adress 0x04 und führe alle aufgetretenen Interrupts aus
                    iPC = 0x04;
                    iReg[0x0B] &= 0x7F; iReg[0x8B] &= 0x7F; //Global Interrupt löschen, damit keine Endlosschleife entsteht
                }
            }
        }

        /*********************************************************************/
        /**   setInterrupt
        **
        **  Setzt einen Interrupt
        **
        **  Ret: void
        **
        **************************************************************************/

        private void setInterrupt()
        {
            //-------Set Interrupts -----
            //Interruptflags setzen wenn jeweilige Bedingung erfüllt
            //RB0/INT set //Nur das 0. Bit abfragen
            if (((iReg[0x06] & 0x01) == 1) && ((iRB & 0x01) == 0))   //Wechsel von 0 auf 1?
            {
                iRB = iRB | 0x01;
                if ((iReg[0x81] & 0x40) > 0)
                {
                    iReg[0x0B] |= 0x02;
                }
            }
            else if (((iReg[0x06] & 0x01) == 0) && ((iRB & 0x01)) > 0) //Wechsel von 1 auf 0?
            {
                iRB = iRB & 0xFE;
                if ((iReg[0x81] & 0x40) == 0)
                {
                    iReg[0x0B] |= 0x02;
                }
            }
            //RB-Port changed (1 of Bit 4-7)
            if (((iReg[0x06] & 0xF0) ^ (iRB & 0xF0)) > 0)
            {
                int hilf;
                hilf = iRB & 0x0F;
                iRB = (iReg[0x06] & 0xF0);
                iRB |= hilf;

                iReg[0x0B] |= 0x01;
            }
            //-------Set Interrupts Ende ---- 
        }

        /*********************************************************************/
        /**   ExecuteCmd
        **
        **  Führt einen Befehl aus
        **
        **  Ret: void
        **
        **************************************************************************/

        private delegate void ExecuteCommandDelegate();
        public void ExecuteCmd()
        {
            if (InvokeRequired)
            {
                var invokeVar = new ExecuteCommandDelegate(ExecuteCmd);
                Invoke(invokeVar);
            }
            else
            {
                String strCurCmd = obDecoder.decode(obFileReader.Commands[iPC]);

                //Befehl in Bits
                int bCmd = obFileReader.Commands[iPC];

                //Execute Command
                tbLastCmd.Text = strCurCmd;
                scanCommand(strCurCmd, bCmd);

                //Spiegelung
                //PC wird gespiegelt
                iReg[0x02] = iPC & 0xFF;
                iReg[0x82] = iPC & 0xFF;
                iReg[0x0A] = (iPC & 0x1F00)>>8;
                iReg[0x8A] = (iPC & 0x1F00)>>8;

                //Register die nicht änderbar sind
                iReg[0x00] = 0;
                iReg[0x80] = 0;
                iReg[0x07] = 0;
                iReg[0x87] = 0;
                if (bank0)  //Bank 1 check
                {
                    //Spiegelung von Bank 0 nach Bank 1
                    iReg[0x83] = iReg[0x03];
                    iReg[0x84] = iReg[0x04];
                    iReg[0x87] = iReg[0x07];
                    iReg[0x8A] = iReg[0x0A];
                    iReg[0x8B] = iReg[0x0B];
                    if ((iReg[0x03] & 0x20) > 0)
                    {
                        bank0 = false;
                    }
                }
                else
                {
                    //Spiegelung von Bank 1 nach Bank 0
                    iReg[0x00] = iReg[0x80];
                    iReg[0x03] = iReg[0x83];
                    iReg[0x04] = iReg[0x84];
                    iReg[0x07] = iReg[0x87];
                    iReg[0x0A] = iReg[0x8A];
                    iReg[0x0B] = iReg[0x8B];
                    if ((iReg[0x03] & 0x20) == 0)
                    {
                        bank0 = true;
                    }
                }
                setInterrupt();
                checkinterrupt();
                FocusListCode(obFileReader.ReferenceList[iPC] - 1);
                if (bSerialCon)
                {
                    sendSerialData();
                }
                refreshReg();
                lRuntime = lCycles * 200;
                checkBreakPoint();
                watchdog();
                simulateTimer0();
            }

        }

        /*********************************************************************/
        /**   FocusListCode
        **
        **  Fokussiert den aktuellen Befehl im ListCode
        **
        **  Ret: void
        **
        **************************************************************************/

        private delegate void FocusListCodeDelegate(int iInRowNumber);
        private void FocusListCode(int iInRowNumber)
        {
            if (InvokeRequired)
            {
                var invokeVar = new FocusListCodeDelegate(FocusListCode);
                Invoke(invokeVar, iInRowNumber);
            }
            else
            {
                listCode.Items[iInRowNumber].Selected = true;
                listCode.Items[iInRowNumber].EnsureVisible();
            }
        }

        /*********************************************************************/
        /**   tutorialToolStripMenuItem_Click
        **
        **  Öffnet die Dokumentation
        **
        **  Ret: void
        **
        **************************************************************************/

        private void tutorialToolStripMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                System.Diagnostics.Process p = new System.Diagnostics.Process();
                p.StartInfo.FileName = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(Application.ExecutablePath), "MisCip-kurz.pdf");
                p.Start();
            }
            catch (Exception ex)
            {
               MessageBox.Show(ex.Message);
            }
        }
    }
}